import os
import datetime
from unittest.case import TestCase
import builders
from database import Database
from mapper import Map, Pom


RIC = 'AGY.L'

__author__ = 'romilly'

class Security(object):
    def __init__(self, name, tidm=None, ric=None, yahoo=None):
        self.name = name
        self.tidm = tidm
        self.ric = ric
        self.yahoo = yahoo

class BasicCandlestick(object):
    def __init__(self, tidm, date, open, high, low, close, volume):
        self.tidm = tidm
        self.date = date
        self.open = open
        self.high = high
        self.low = low
        self.close = close
        self.volume = volume

class DatabaseTestCase(TestCase):

    def pathToDatabase(self):
        return 'data/static.sqlite'

    def setUp(self):
        self.deleteDatabaseFile()
        self.db = Database(self.pathToDatabase())
        self.db.open()
        self.db.execute('CREATE TABLE SECURITY(NAME VARCHAR(50), TIDM VARCHAR(5), RIC VARCHAR(10), YAHOO VARCHAR(10), COMMENTS VARCHAR(255))')

    def deleteDatabaseFile(self):
        if os.path.isfile(self.pathToDatabase()):
            os.remove(self.pathToDatabase())
        
    def tearDown(self):
        self.db.close()
        
    def assertRowCountIs(self, expectedCount, table='SECURITY'):
        count = self.db.executeQuery('SELECT COUNT(*) FROM %s' % table)[0][0]
        self.assertEqual(expectedCount, count)

class BuilderForMapTests():

    def securityMap(self):
        return (builders.MapBuilder(Security).
                    withColumn('NAME', 50).
                    withColumn('TIDM', 5).
                    withColumn('RIC', 10).
                    withColumn('YAHOO', 10)
                    .build())

    def candlestickMap(self):
        return (builders.MapBuilder(BasicCandlestick)
                .withColumn('tidm', 10)
                .withDateColumn('date')
                .withDecimalColumn('open', 8, 2)
                .withDecimalColumn('high', 8, 2)
                .withDecimalColumn('low', 8, 2)
                .withDecimalColumn('close', 8, 2)
                .withIntegerColumn('volume', 8)
                .build())

class TestClassToTableMap(DatabaseTestCase):

    def setUp(self):
        super(TestClassToTableMap, self).setUp()
        self.map = BuilderForMapTests().securityMap()

    def testCanFindObjectsById(self):
        self.db.execute("INSERT INTO SECURITY VALUES('Allergy','AGY', NULL, NULL, 'FOO')")
        self.db.commit()
        security = self.map.findById(self.db, 1)
        self.assertTrue(isinstance(security, Security))
        self.assertEqual(security.name,'Allergy')
        self.assertEqual(security.tidm,'AGY')

    def testInsertsNewObject(self):
        self.assertRowCountIs(0)
        self.map.save(self.db, Security('Allergy', 'AGY'))
        self.assertRowCountIs(1)

    def testSetsTheIdForAnInsertedObject(self):
        securityToSave = Security('Allergy','AGY')
        self.assertRowCountIs(0)
        self.map.save(self.db, securityToSave)
        self.assertHasAttribute(securityToSave, 'id')

    def testUpdatesAnExistingObject(self):
        securityToSave = Security('Allergy','AGY')
        self.assertEqual(securityToSave.ric, None)
        self.map.save(self.db, securityToSave)
        id = securityToSave.id
        securityToSave.ric = RIC
        self.map.save(self.db, securityToSave)
        securityFromDatabase = self.map.findById(self.db, id)
        self.assertEquals(securityFromDatabase.ric, RIC)

    def testOnlyInsertsMappedColumns(self):
         tableModelWithExtraColumn = (builders.TableModelBuilder('SECURITY')
                        .withColumn('NAME', 50)
                        .withColumn('TIDM', 5)
                        .withColumn('RIC', 10)
                        .withColumn('YAHOO', 10)
                        .withColumn('COMMENTS', 255)
                        .build())
         extendedMap = Map(self.map.classModel(), tableModelWithExtraColumn, self.map.fieldToColumnMaps())
         securityToSave = Security('Allergy','AGY')
         extendedMap.save(self.db, securityToSave)
         self.assertRowCountIs(1)

    def testCanHandleDatesAndNumbers(self):
        candlestickMap = BuilderForMapTests().candlestickMap()
        self.db.execute(candlestickMap.tableModel().createTableStatement())
        candlestick = BasicCandlestick('BAY', datetime.date(2011, 3, 21),231.1, 247.3, 223.0, 234.9, 1566034)
        candlestickMap.save(self.db, candlestick)
        self.assertRowCountIs(1, 'BASIC_CANDLESTICK')

    def assertHasAttribute(self, obj, attribute):
        self.assertTrue(attribute in obj.__dict__, 'should have %s set' % attribute) # try this without msg to see why messages are so important!

class TestPom(DatabaseTestCase):

    def setUp(self):
        super(TestPom, self).setUp()
        self.pom = Pom(self.db)

    def configurePomWithTwoMappedClasses(self):
        self.pom.addMap(BuilderForMapTests().securityMap())
        self.pom.addMap(BuilderForMapTests().candlestickMap())

    def testCanSaveMappedObjects(self):
        self.configurePomWithTwoMappedClasses()
        self.pom.save(Security('Allergy','AGY'))
        self.assertRowCountIs(1)

    def testCanRetrieveMappedObjects(self):
        self.configurePomWithTwoMappedClasses()
        self.db.execute("INSERT INTO SECURITY VALUES('Allergy','AGY', 'AGY.L', NULL, 'IGNORED')")
        security = self.pom.findById(Security, 1)
        self.assertEqual(security.name,'Allergy')


